package splash.core.execution;

import javax.swing.JOptionPane;
import javax.imageio.ImageIO;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Graphics2D;

import java.net.ServerSocket;

import java.io.IOException;
import java.io.File;

import splash.core.connection.PropertySet;
import splash.core.connection.Command;
import splash.core.connection.CommandType;
import splash.core.connection.ConsoleSession;

import splash.core.connection.ResponseCode;
import splash.core.connection.Response;
import splash.core.connection.Property;

import splash.core.Util;

public class Execute {
        public static ResponseCode executeCommand(Command c, PropertySet ps,
                ConsoleSession cs)
        {
                /* Assume that user is allowed to do spec. action */
                if(c.getType().equals(CommandType.MESSAGE))
                {
                    return showMessage(ps, cs);
                }

                if(c.getType().equals(CommandType.SHUTDOWN))
                {
                    return shutdown(ps, cs);
                }

                if(c.getType().equals(CommandType.DELETE))
                {
                     return delete(ps, cs);
                }

                if(c.getType().equals(CommandType.EXECUTE))
                {
                     return execute(ps, cs);
                }

                if(c.getType().equals(CommandType.READ))
                {
                    return read(ps, cs);
                }

                if(c.getType().equals(CommandType.WRITE))
                {
                    return write(ps, cs);
                }

                if(c.getType().equals(CommandType.SCREEN))
                {
                    return screen(ps, cs);
                }
                
                if(c.getType().equals(CommandType.EXIT))
                {
                    /* Shut software down */
                    cs.getConcoleUI().stopServer();
                    return ResponseCode.OK;
                }
                
                if(c.getType().equals(CommandType.PRESENTATION))
                {
                    return presentation(ps, cs);
                }
                
                if(c.getType().equals(CommandType.MOUSE))
                {
                    return mouse(ps, cs);
                }

                return ResponseCode.NOT_IMPLEMENTED;
        }

        private static ResponseCode showMessage(PropertySet ps, ConsoleSession cs)
        {
                /* Display Message */
                Response r = cs.getResponse();
                String message = "";
                String from = "";
                int type = JOptionPane.PLAIN_MESSAGE;

                for(int i = 0; i < ps.size(); i++)
                {
                    if(ps.get(i).getName().equalsIgnoreCase("MSG"))
                        message = ps.get(i).getValue();
                    if(ps.get(i).getName().equalsIgnoreCase("FROM"))
                        from = ps.get(i).getValue();
                    if(ps.get(i).getName().equalsIgnoreCase("TYPE"))
                    {
                        if(ps.get(i).getValue().equalsIgnoreCase("ERR"))
                            type = JOptionPane.ERROR_MESSAGE;
                        if(ps.get(i).getValue().equalsIgnoreCase("MSG"))
                            type = JOptionPane.INFORMATION_MESSAGE;
                        if(ps.get(i).getValue().equalsIgnoreCase("WAR"))
                            type = JOptionPane.WARNING_MESSAGE;
                    }
                }
                /* Open message in new thread */
                new Thread(new MessageThread(message, from, type)).start();
                return ResponseCode.OK;
        }

        private static ResponseCode shutdown(PropertySet ps, ConsoleSession cs)
        {
                /* Shut a computer down */
                /* Check for OS */
                String os = System.getProperty("os.name").toLowerCase();
                String command = "shutdown" + " ";
                String type = "";
                for(int i = 0; i < ps.size(); i++)
                {
                    if(ps.get(i).getName().equalsIgnoreCase("type"))
                        type = ps.get(i).getValue();
                }

                if(os.indexOf("win") > -1)
                {
                    if(type.equalsIgnoreCase("shutdown"))
                    {
                        command += "-s";
                    }

                    if(type.equalsIgnoreCase("reboot"))
                    {
                        command += "-r";
                    }

                    if(type.equalsIgnoreCase("cancel"))
                    {
                        command += "-a";
                    }
                }
                else /* Assume Mac OSX or Unix */
                {
                    if(type.equalsIgnoreCase("shutdown"))
                    {
                        command += "-h 60";
                    }

                    if(type.equalsIgnoreCase("reboot"))
                    {
                        command += "-r 60";
                    }

                    if(type.equalsIgnoreCase("cancel"))
                    {
                        command += "-c";
                    }
                }

                try
                {
                    Runtime.getRuntime().exec(command);
                    return ResponseCode.OK;
                }
                catch(IOException e)
                {
                    e.printStackTrace();
                    return ResponseCode.NOT_FOUND;
                }

        }

        private static ResponseCode delete(PropertySet ps, ConsoleSession cs)
        {
            /* Delete file */
            File f;
            String fn = "";
            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("file"))
                {
                    fn = ps.get(i).getValue();
                }
            }

            System.out.println("Brisem " + fn);
            f = new File(fn);
            if(!f.exists())
            {
                return ResponseCode.NOT_FOUND;
            }

            if(f.delete())
            {
                return ResponseCode.OK;
            }
            else
            {
                return ResponseCode.NOT_FOUND;
            }
        }

        private static ResponseCode execute(PropertySet ps, ConsoleSession cs)
        {
            String command = "";
            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("command"))
                {
                    command = ps.get(i).getValue();
                }
            }

            try
            {
                Runtime.getRuntime().exec(command);
                return ResponseCode.OK;
            }
            catch(IOException e)
            {
                return ResponseCode.FAILED;
            }
        }

        private static ResponseCode read(PropertySet ps, ConsoleSession cs)
        {
            String file = "";
            File f;
            Response r = cs.getResponse();
            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("file"))
                {
                    file = ps.get(i).getValue();
                }
            }

            f = new File(file);
            if(!f.exists())
            {
                return ResponseCode.NOT_FOUND;
            }

            /* Directory listing or load file */

            if(f.isDirectory())
            {
                r.addProperty(new Property("type","dirlist"));
            }
            else
            {
                r.addProperty(new Property("type","file"));
            }

            ServerSocket s = null;
            try
            {
                s = new ServerSocket(cs.getSettings().getSecondaryPort());
            }
            catch(IOException e)
            {
            }
            
            /* Not our time yet */
            //String userSession = cs.getSSID(); 

            new Thread(new FileThread(f, s, true)).start();
            r.addProperty(new Property("port", "" + s.getLocalPort()));

            return ResponseCode.OK;
        }

        private static ResponseCode screen(PropertySet ps, ConsoleSession cs)
        {
            Response r = cs.getResponse();
            int h = 0;
            int w = 0;

            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("width"))
                {
                    if(!ps.get(i).getValue().matches("\\D"))
                    {
                            w = Integer.parseInt(ps.get(i).getValue());
                    }
                }

                if(ps.get(i).getName().equalsIgnoreCase("height"))
                {
                    if(!ps.get(i).getValue().matches("\\D"))
                    {
                            h = Integer.parseInt(ps.get(i).getValue());
                    }
                }
            }

            Robot ro = null;
            try
            {
                ro = new Robot();
            }
            catch(AWTException ae)
            {}

            Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
            BufferedImage bi = ro.createScreenCapture(new Rectangle(dim.getSize()));

            BufferedImage resizedImage = new BufferedImage(w, h,
                                        BufferedImage.TYPE_INT_RGB);
            Graphics2D g = resizedImage.createGraphics();
            g.drawImage(bi, 0, 0, w, h, null);
            g.dispose();

            /* Calculate file size */
            long size = 0;
            try
            {
                File tmp = File.createTempFile(Util.md5(Math.random() + ""), null);
                ImageIO.write(resizedImage, "jpg", tmp);
                size = tmp.length();
            }
            catch(IOException e)
            {
            }

            ServerSocket s = null;
            try
            {
                s = new ServerSocket(cs.getSettings().getSecondaryPort());
            }
            catch(IOException e)
            {
                /* if prefered port is already bound, switch to free one */
                try
                {
                    s = new ServerSocket(0);
                }
                catch(Exception ei)
                {

                }
            }
            
            //String userSession = cs.getSSID();
            r.addProperty(new Property("port", "" + s.getLocalPort()));
            r.addProperty(new Property("size", "" + size));
            new Thread(new ImageThread(s, resizedImage)).start(); 

            return ResponseCode.OK;
        }


        private static ResponseCode write(PropertySet ps, ConsoleSession cs)
        {
            Response r = cs.getResponse();
            String file = "";
            String mkdir = "";
            File f = null;

            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("write"))
                {
                    file = ps.get(i).getValue();
                }

                if(ps.get(i).getName().equalsIgnoreCase("mkdir"))
                {
                    mkdir = ps.get(i).getValue();
                }
            }

            if(!mkdir.equals(""))
            {

                File mkd = new File(mkdir);
                if(mkd.mkdir())
                {
                    return ResponseCode.OK;
                }
                else
                {
                    return ResponseCode.NOT_PREMITTED;
                }
            }
            else
            {
                f = new File(file);
            }

            ServerSocket s = null;
            try
            {
                s = new ServerSocket(cs.getSettings().getSecondaryPort());
            }
            catch(IOException e)
            {
            }
            
            /* It should be valid since we're executing a command. */
            //String userSession = cs.getSSID(); 
            
            new Thread(new FileThread(f, s, true)).start();
            r.addProperty(new Property("port", "" + s.getLocalPort()));

            return ResponseCode.OK;
        }
        
        private static ResponseCode presentation(PropertySet ps, ConsoleSession cs)
        {
             Response resp = cs.getResponse();
            /* Presentation mode button (key) to emulate */
            String button = "";
            Robot r = null;
            try
            {
		r = new Robot();
            }
            catch(AWTException awte)
            {
            }
			
            for(int i = 0; i < ps.size(); i++)
            {
                if(ps.get(i).getName().equalsIgnoreCase("press"))
                {
                    button = ps.get(i).getValue();
                }
            }
            
            if(button.equalsIgnoreCase("left"))
            {
            	r.keyPress(KeyEvent.VK_LEFT);
            	r.keyRelease(KeyEvent.VK_LEFT);
            }
            else if(button.equalsIgnoreCase("right"))
            {
            	r.keyPress(KeyEvent.VK_RIGHT);
            	r.keyRelease(KeyEvent.VK_RIGHT);
            }
            else if(button.equalsIgnoreCase("up"))
            {
            	r.keyPress(KeyEvent.VK_UP);
            	r.keyRelease(KeyEvent.VK_UP);
            }
            else if(button.equalsIgnoreCase("down"))
            {
            	r.keyPress(KeyEvent.VK_DOWN);
            	r.keyRelease(KeyEvent.VK_DOWN);
            }
            else if(button.equalsIgnoreCase("black"))
            {
            	r.keyPress(KeyEvent.VK_B);
            	r.keyRelease(KeyEvent.VK_B);
            }
            else if(button.equalsIgnoreCase("white"))
            {
            	r.keyPress(KeyEvent.VK_W);
            	r.keyRelease(KeyEvent.VK_W);
            }
            else if(button.equalsIgnoreCase("exit"))
            {
            	r.keyPress(KeyEvent.VK_ESCAPE);
            	r.keyRelease(KeyEvent.VK_ESCAPE);
            }
            else
            {
            	return ResponseCode.NOT_IMPLEMENTED;
            }

            return ResponseCode.OK;
        }
        
        private static ResponseCode mouse(PropertySet ps, ConsoleSession cs)
        {
            Response resp = cs.getResponse();
            ServerSocket s = null;
            try
            {
                s = new ServerSocket(cs.getSettings().getSecondaryPort());
            }
            catch(IOException e)
            {
                /* if prefered port is already bound, switch to free one */
                try
                {
                    s = new ServerSocket(0);
                }
                catch(Exception ei)
                {

                }
            }
            
            /* Set up a robot control */
            Robot r;
            try
            {
            	r = new Robot();
            }
            catch(AWTException awte)
            {
            	return ResponseCode.NOT_PREMITTED;
            }
            
            //String userSession = cs.getSSID(); 
            resp.addProperty(new Property("port", "" + s.getLocalPort()));
            new Thread(new MouseThread(s, r)).start();

            return ResponseCode.OK;
        }

}
